package com.harmony.rpc.remote;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.task.controller.TaskController;
import com.task.controller.control.Control;
import com.task.controller.executor.Executor;
import com.harmony.rpc.entity.RemoteRequest;
import com.harmony.rpc.entity.RemoteResponse;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.*;

public class ProxyRemote extends RemoteObject implements IRemoteBroker {

    private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.INFO, 0, ProxyRemote.class.getCanonicalName());

    private static final String descriptor = "快速远程代理";

    private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

    private TaskController taskController;

    private Executor.ExecuteEvent executeEvent;

    private Control control;

    public ProxyRemote() {
        super(descriptor);
        taskController = TaskController.getInstance();
        control = taskController.getControl();
    }

    @Override
    public IRemoteObject asObject() {
        return this;
    }

    @Override
    public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
        String string = data.readString();
        RemoteRequest remoteRequest = gson.fromJson(string, RemoteRequest.class);
        control.execute(remoteRequest.getResource(), remoteRequest.getData(), executeEvent != null ? executeEvent : objects -> {
            if (objects.length > 1) {
                HiLog.warn(LABEL_LOG, "异常的数据长度，默认只支持1个长度的返回值");
                return;
            }
            RemoteResponse remoteResponse = new RemoteResponse();
            Object o = objects[0];
            remoteRequest.setData(gson.toJson(o));
            remoteResponse.setId(remoteRequest.getId());
            reply.writeString(gson.toJson(remoteResponse));
        });
        return true;
    }

    public Control getControl() {
        return control;
    }

    public void setControl(Control control) {
        this.control = control;
    }

    /**
     * 调用此方法，向远程发送功能申请
     *
     * @param code          ability启动标识码，连接ability时，使用的标识码
     * @param remoteRequest 发送此对象，向远程发送功能申请
     * @param executeEvent  返回值处理对象，默认情况下，发送申请后，会等待远程的返回值，因此在设计此对象时，最好考虑超时的问题
     * @throws RemoteException 远程对象发生异常时，抛出此异常
     */
    public void sendRequest(int code, RemoteRequest remoteRequest, Executor.ExecuteEvent executeEvent) throws RemoteException {
        if (remoteRequest == null) {
            throw new IllegalArgumentException("不能将null作为申请，发送给执行端");
        }
        MessageParcel data = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        try {
            data.writeString(gson.toJson(remoteRequest));
            sendRequest(code, data, reply, new MessageOption(MessageOption.TF_SYNC));
            String string = reply.readString();
            if (executeEvent != null) {
                executeEvent.executeListener(string);
            }
        } catch (RemoteException remoteException) {
            remoteException.printStackTrace();
            throw remoteException;
        } finally {
            if (data != null) {
                data.reclaim();
            }
            if (reply != null) {
                reply.reclaim();
            }
        }
    }

    public void sendRequest(int code, IRemoteObject remoteObject, RemoteRequest remoteRequest, Executor.ExecuteEvent executeEvent) throws RemoteException {
        if (remoteRequest == null) {
            throw new IllegalArgumentException("不能将null作为申请，发送给执行端");
        }
        MessageParcel data = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        try {
            data.writeString(gson.toJson(remoteRequest));
            remoteObject.sendRequest(code, data, reply, new MessageOption(MessageOption.TF_SYNC));
            String string = reply.readString();
            if (executeEvent != null) {
                executeEvent.executeListener(string);
            }
        } catch (RemoteException remoteException) {
            remoteException.printStackTrace();
            throw remoteException;
        } finally {
            if (data != null) {
                data.reclaim();
            }
            if (reply != null) {
                reply.reclaim();
            }
        }
    }

    public void setExecuteEvent(Executor.ExecuteEvent executeEvent) {
        this.executeEvent = executeEvent;
    }
}
